package com.server.util;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 资源文件读取工具
 */
public class PropertiesFileUtil {

    // 当打开多个资源文件时，缓存资源文件
    private static HashMap<String, PropertiesFileUtil> configMap = new HashMap<String, PropertiesFileUtil>();
    // 打开文件时间，判断超时使用
    private Date loadTime = null;
    // 资源文件
    private ResourceBundle resourceBundle = null;
    // 默认资源文件名称
    private static final String NAME = "config";
    // 缓存时间
    private static final Integer TIME_OUT = 60 * 1000;

    // 私有构造方法，创建单例
    private PropertiesFileUtil(String name) {
        this.loadTime = new Date();
        this.resourceBundle = ResourceBundle.getBundle(name);
    }

    public static synchronized PropertiesFileUtil getInstance() {
        return getInstance(NAME);
    }

    public static synchronized PropertiesFileUtil getInstance(String name) {
        PropertiesFileUtil conf = configMap.get(name);
        if (null == conf) {
            conf = new PropertiesFileUtil(name);
            configMap.put(name, conf);
        }
        // 判断是否打开的资源文件是否超时1分钟
        if ((System.currentTimeMillis() - conf.getLoadTime().getTime()) > TIME_OUT) {
            conf = new PropertiesFileUtil(name);
            configMap.put(name, conf);
        }
        return conf;
    }

    // 根据key读取value
    public String get(String key) {
        try {
            String value = resourceBundle.getString(key);
            value = new String(value.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            return value;
        } catch (MissingResourceException e) {
            return "";
        }
    }

    // 根据key读取value(整形)
    public Integer getInt(String key) {
        try {
            String value = resourceBundle.getString(key);
            return Integer.parseInt(value);
        } catch (MissingResourceException e) {
            return null;
        }
    }

    // 根据key读取value(布尔)
    public boolean getBool(String key) {
        try {
            String value = resourceBundle.getString(key);
            if ("true".equals(value)) {
                return true;
            }
            return false;
        } catch (MissingResourceException e) {
            return false;
        }
    }

    public Date getLoadTime() {
        return loadTime;
    }


    public static void initFromProp(Properties properties, Object obj) throws Exception {
        initFromProp(properties, "", obj);
    }

    //根据对象的属性赋值
    public static void initFromProp(Properties properties, String propProfix, Object obj) throws Exception {
        if (properties == null || obj == null) {
            return;
        }
        propProfix = propProfix == null ? "" : propProfix;

        for (String propName : properties.stringPropertyNames()) {
            try {
                String propValue = properties.getProperty(propName);
                String objFieldName = propName.replaceFirst(propProfix, "");

                Field declaredField = getDeclaredField(obj.getClass(), objFieldName);
                if (declaredField == null) {
                    continue;
                }

                declaredField.setAccessible(true);
                Class clazz = declaredField.getType();
                String cn = clazz.getSimpleName();
                Object fileValue = null;
                if (cn.equals("byte") || cn.equals("Byte")) {
                    fileValue = Byte.parseByte(propValue);
                } else if (cn.equals("short") || cn.equals("Short")) {
                    fileValue = Short.parseShort(propValue);
                } else if (cn.equals("int") || cn.equals("Integer")) {
                    fileValue = Integer.parseInt(propValue);
                } else if (cn.equals("long") || cn.equals("Long")) {
                    fileValue = Long.parseLong(propValue);
                } else if (cn.equals("boolean") || cn.equals("Boolean")) {
                    fileValue = Boolean.parseBoolean(propValue);
                } else if (cn.equals("String")) {
                    fileValue = propValue;
                } else if (Enum.class.isAssignableFrom(clazz) && convertEnum(clazz, propValue) != null) {
                    fileValue = convertEnum(clazz, propValue);
                } else {
                    continue;
                }
                declaredField.set(obj, fileValue);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static Field getDeclaredField(Class clazz, String objFieldName) throws Exception {
        if (clazz == null || objFieldName == null) {
            return null;
        }
        Field declaredField = null;
        try {
            declaredField = clazz.getDeclaredField(objFieldName);
        } catch (NoSuchFieldException e) {
        } catch (SecurityException e) {
        }
        if (declaredField != null) {
            return declaredField;
        }
        Class superclass = clazz.getSuperclass();
        return getDeclaredField(superclass, objFieldName);
    }

    private static Enum convertEnum(Class clazzEnum, String nameEnum) {
        if (clazzEnum == null || nameEnum == null) {
            return null;
        }
        if (!Enum.class.isAssignableFrom(clazzEnum)) {
            return null;
        }
        try {
            return Enum.valueOf(clazzEnum, nameEnum);
        } catch (Exception e) {

        }
        return null;
    }

    public static Properties getPropertiesFromClasspath(String configFileName) throws Exception {
        Properties properties = new Properties();
        InputStream is = null;
        try {
            is = PropertiesFileUtil.class.getResourceAsStream("/" + configFileName);
            properties.load(is);
        } finally {
            if (is != null) {
                is.close();
            }
        }

        return properties;
    }

    public static Properties getPropertiesFromAbs(String configFileName) throws Exception {
        Properties properties = new Properties();
        InputStream is = null;
        try {
            is = new FileInputStream(configFileName);
            properties.load(is);
        } finally {
            if (is != null) {
                is.close();
            }
        }

        return properties;
    }
}
